package com.fzf.org.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fzf.org.dao.entities.BlogDO;
import com.fzf.org.dao.entities.DraftDO;
import com.fzf.org.dto.resp.blog.PictureCheckRespDTO;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.util.MultiValueMap;
import org.springframework.util.LinkedMultiValueMap;
import com.fzf.org.dao.mapper.BlogMapper;
import com.fzf.org.dao.mapper.BlogPicMapper;
import com.fzf.org.dao.mapper.DraftMapper;
import com.fzf.org.dao.mapper.DraftPicMapper;
import com.fzf.org.dto.resp.blog.DraftDTO;
import com.fzf.org.dto.req.draft.DraftReqDTO;
import com.fzf.org.exception.BizException;
import com.fzf.org.exception.BizExceptionTypeEnum;
import com.fzf.org.page.PageRequest;
import com.fzf.org.page.PageResponse;
import com.fzf.org.service.DraftsService;
import com.fzf.org.toolkit.BasicContext;
import lombok.RequiredArgsConstructor;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class DraftsServiceImpl implements DraftsService {


    private final DraftPicMapper draftPicMapper;
    private final BlogPicMapper blogPicMapper;

    private final DraftMapper draftMapper;
    private final BlogMapper blogMapper;
    private final RestTemplate restTemplate;
    private final FileStorageService fileStorageService;


    @Override
    public PageResponse<DraftDTO> listUsersDrafts(PageRequest pageRequest) {
        if (pageRequest == null) {
            throw new BizException(BizExceptionTypeEnum.PARAM_ERROR);
        }

        IPage<DraftDO> page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize());
        LambdaQueryWrapper<DraftDO> wrapper = new LambdaQueryWrapper<DraftDO>()
                .eq(DraftDO::getUserId, BasicContext.getBasicId());

        IPage<DraftDO> resultPage = draftMapper.selectPage(page, wrapper);
        List<DraftDTO> convertRecords = resultPage.getRecords().stream().map(
                draftDO -> BeanUtil.copyProperties(draftDO, DraftDTO.class)
        ).toList();

        return new PageResponse<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal(), convertRecords);
    }

    @Override
    public DraftDTO showDraftDetail(Long draftID) {
        DraftDO draft = draftMapper.selectOne(new LambdaQueryWrapper<DraftDO>()
                .eq(DraftDO::getUserId, BasicContext.getBasicId())
                .eq(DraftDO::getId, draftID));
        if (null == draft) {
            throw new BizException(BizExceptionTypeEnum.DRAFT_NOT_EXIST_ERROR);
        }

        return BeanUtil.copyProperties(draft, DraftDTO.class);
    }

    @Override
    public Long createNewDraft() {
        DraftDO draft = DraftDO.builder().userId(BasicContext.getBasicId()).build();
        int insert = draftMapper.insert(draft);
        if (insert != 1) {
            throw new BizException(BizExceptionTypeEnum.DRAFT_INSERT_ERROR);
        }
        return draft.getId();
    }

    @Override
    public void saveBlogDraft(DraftReqDTO draftID) {
        DraftDO draftDO = draftMapper.selectOne(
                new LambdaQueryWrapper<DraftDO>().eq(DraftDO::getId, draftID.getId())
        );
        if (null == draftDO) {// 查不到
            throw new BizException(BizExceptionTypeEnum.DRAFT_NOT_EXIST_ERROR);
        }
        if (!BasicContext.getBasicId().equals(draftDO.getUserId())) {// 查出来不是当前用户的
            throw new BizException(BizExceptionTypeEnum.ILLEGAL_DRAFT_GET_ERROR);
        }

        draftDO.setTitle(draftID.getTitle());
        draftDO.setContent(draftID.getContent());
        int update = draftMapper.updateById(draftDO);

        if (update != 1) {
            throw new BizException(BizExceptionTypeEnum.DRAFT_UPDATE_ERROR);
        }
    }

    @Override
    public void delBlogDraft(Long draftID) {
        int delete = draftMapper.delete(new LambdaQueryWrapper<DraftDO>()
                .eq(DraftDO::getUserId, BasicContext.getBasicId())
                .eq(DraftDO::getId, draftID));
        if (delete != 1) {
            throw new BizException(BizExceptionTypeEnum.DRAFT_NOT_EXIST_ERROR);
        }
    }

    private final String REMOTE_ALGO_IMAGE_URL = "http://159.75.72.79:9236/predict_image";
    private final String REMOTE_ALGO_TEXT_URL = "http://159.75.72.79:9236/text_predict";

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Long pubBlogDraft(DraftReqDTO draft) {
        if (!checkContent(draft)) {
            saveBlogDraft(draft);// 回写草稿
            throw new BizException(BizExceptionTypeEnum.DRAFT_CONTENT_ERROR);
        } else {
            int delete = draftMapper.delete(new LambdaQueryWrapper<DraftDO>()
                    .eq(DraftDO::getUserId, BasicContext.getBasicId())
                    .eq(DraftDO::getId, draft.getId()));
            if (delete != 1) {
                throw new BizException(BizExceptionTypeEnum.DRAFT_NOT_EXIST_ERROR);
            }

            BlogDO blog = BlogDO.builder()
                    .userId(BasicContext.getBasicId())
                    .title(draft.getTitle())
                    .content(draft.getContent())
                    .status(2) // 经过上述审核才会最终发布
                    .build();
            int insert = blogMapper.insert(blog);
            if (insert != 1) {
                throw new BizException(BizExceptionTypeEnum.BLOG_INSERT_ERROR);
            }

            return blog.getId();
        }
    }


    @Override
    public PictureCheckRespDTO uploadPic(MultipartFile pic, Long draftId) {
        String originalFilename = pic.getOriginalFilename();
        String type = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        if ("png".equals(type) || "jpg".equals(type) || "jpeg".equals(type)) {
            String url = Optional.ofNullable(fileStorageService.of(pic).upload()).map(FileInfo::getUrl).orElseThrow(
                    () -> new BizException(BizExceptionTypeEnum.COS_UPLOAD_ERROR)
            );
            //把接收到的 MultipartFile pic 图片通过 restTemplate发送给另一个服务器进行审查图片
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.MULTIPART_FORM_DATA);
                InputStream inputStream = pic.getInputStream();
                Resource resource = new MultipartInputStreamFileResource(inputStream, originalFilename, pic.getSize());
                MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
                body.add("file", resource);  //

                HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

                RestTemplate restTemplate = new RestTemplate();
                ResponseEntity<String> response = restTemplate.postForEntity(REMOTE_ALGO_IMAGE_URL, requestEntity, String.class);

                // 根据返回结果解析（如需要 JSON 可用 ObjectMapper）
                String result = response.getBody();
                Map map = objectMapper.readValue(result, Map.class); //
                System.out.println("图片审查返回结果：" + result); // 图片审查返回结果：{"predicted_class":"dog"}
                return PictureCheckRespDTO.builder().url(url).animal((String)map.get("predicted_class")).build();
            } catch (IOException e) {
                throw new BizException(BizExceptionTypeEnum.COS_UPLOAD_ERROR);
            }
        } else {
            throw new BizException(BizExceptionTypeEnum.NOT_ALLOWED_FILE_TYPE);
        }
    }

    public boolean checkContent(DraftReqDTO draftReqDTO) {
        final int maxAttempts = 3;
        final long delayMillis = 1000;
        int attempts = 0;

        while (attempts < maxAttempts) {
            try {
                System.out.println("--------------- Attempt: " + (attempts + 1));

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);

                Map<String, String> requestBody = new HashMap<>();
                requestBody.put("text", draftReqDTO.getContent());

                HttpEntity<Map<String, String>> request = new HttpEntity<>(requestBody, headers);

                ResponseEntity<String> response = restTemplate.postForEntity(REMOTE_ALGO_TEXT_URL, request, String.class);

                Map<String, Object> responseMap = objectMapper.readValue(response.getBody(), Map.class);


                System.out.println(responseMap.get("predicted_class"));
//                return "中性".equals(responseMap.get("predicted_class")); // 积极   消极
                return !"消极".equals(responseMap.get("predicted_class")); // 积极  中性 消极
            } catch (RestClientException | JsonProcessingException e) {
                attempts++;
                System.err.println("远程请求失败，第 " + attempts + " 次尝试: " + e.getMessage());

                if (attempts >= maxAttempts) {
                    throw new RuntimeException("远程调用失败，超过最大重试次数", e);
                }
                try {
                    Thread.sleep(delayMillis); // 延迟后重试
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试等待被中断", ie);
                }
            }
        }
        return false;
    }



    public static class MultipartInputStreamFileResource extends InputStreamResource {

        private final String filename;
        private final long contentLength;

        public MultipartInputStreamFileResource(InputStream inputStream, String filename, long contentLength) {
            super(inputStream);
            this.filename = filename;
            this.contentLength = contentLength;
        }

        @Override
        public String getFilename() {
            return this.filename;
        }

        @Override
        public long contentLength() throws IOException {
            return this.contentLength;
        }
    }

}
